/**
 * Odontosis - (2008 - Eclipse 3.3 - JDK1.6 Update 3) 
 */
package com.odontosis.as;

import java.lang.reflect.ParameterizedType;
import java.util.List;

import javax.persistence.Query;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;

import com.odontosis.OdontosisObject;
import com.odontosis.entidade.OdontosisBusinessObject;
import com.odontosis.util.HibernateUtil;

/**
 * Data Access Object geral do sistema Odontosis.
 * @param T tipo da entidade na qual o DAO vai trabalhar. Usado pelos mtodos recuperarQuantidadeBOs e
 * 		recuperarTodosBOs.
 * @author Oto
 * @version
 * ltima modificao: $Author$<br>
 * Verso: $Revision$ $Date$
 */
public abstract class OdontosisDataAccessObject<T extends OdontosisBusinessObject> extends OdontosisObject {
	private Class<?> entityClass; 
	
	/**
	 * Construtor padro.
	 */
	public OdontosisDataAccessObject() {
		entityClass = (Class<?>) ((ParameterizedType) 
				getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	}
	
		
	public void delete(T entidade) {
		Session session = HibernateUtil.currentSession();
		Transaction transaction = session.beginTransaction();
		try {
			session.delete(entidade);
			transaction.commit();
		} catch (Exception e) {
			transaction.rollback();
		}
	}

	public void evict(T entidade) {
		Session session = HibernateUtil.currentSession();
		session.evict(entidade);
	}

	@SuppressWarnings("unchecked")
	public T load(Long id) {
		HibernateUtil.closeSession();
		Session session = HibernateUtil.currentSession();
		session.clear();
		if (id == null) {
			throw new IllegalArgumentException("Parameter id cannot be null");
		}
		session.evict(session.get(entityClass, id));
		
		T objeto = (T) session.get(entityClass, id);
		session.refresh(objeto);
		return objeto;
	}

	@SuppressWarnings("unchecked")
	public T merge(T entidade) {
		Session session = HibernateUtil.currentSession();
		return (T) session.merge(entidade);
	}

	public void save(T entidade) {
		Session session = HibernateUtil.currentSession();
		Transaction transaction = session.beginTransaction();
		try {
			session.save(entidade);
			transaction.commit();
		} catch (Exception e) {
			transaction.rollback();
			throw new RuntimeException("Erro ao salvar entidade");
		}
	}

	public void saveOrUpdate(T entidade) {
		Session session = HibernateUtil.currentSession();
		Transaction transaction = session.beginTransaction();
		try {
			session.saveOrUpdate(entidade);
			transaction.commit();
		} catch (Exception e) {
			transaction.rollback();
			e.printStackTrace();
			throw new RuntimeException("Erro ao salvar ou updatar entidade");
		}
		
	}

	
	public void update(T entidade) {
		HibernateUtil.closeSession();
		Session session = HibernateUtil.currentSession();
		Transaction transaction = session.beginTransaction();
		
		try {
			session.update(entidade);
			transaction.commit();
		} catch (Exception e) {
			transaction.rollback();
			throw new RuntimeException("Erro ao updatar entidade");
		}
		
		
	}

	public Class<?> getEntityClass() {
		return entityClass;
	}

	public void setEntityClass(Class<T> entityClass) {
		this.entityClass = entityClass;
	}

	public Session getSession() {
		Session session = HibernateUtil.currentSession();
		return session;
	}
	
	public void refresh(T entidade) {
		Session session = HibernateUtil.currentSession();
		session.refresh(entidade);
	}

	
	@SuppressWarnings("unchecked")
	public List<T> findAll() {
		HibernateUtil.closeSession();
		Session session = HibernateUtil.currentSession();
		Criteria criteria = session.createCriteria(entityClass);
		criteria.add(Restrictions.eq("ativo", true));
		criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
		criteria.addOrder(Order.desc("id"));
		return criteria.list();

	}
	
	public void excluirLogicamente(T entidade){
		Session session = HibernateUtil.currentSession();
		Transaction transaction = session.beginTransaction();
		try {
			entidade.setAtivo(false);
			session.update(entidade);
			transaction.commit();
		} catch (Exception e) {
			transaction.rollback();
			log.debug(e.toString());
		}
	}

	
}
